package com.alinks.modbus.core.codec.ascii;

import com.alinks.modbus.core.codec.AbstractModbusCodec;
import com.alinks.modbus.core.exception.ModbusSlaveCodeEnum;
import com.alinks.modbus.core.frame.ASCIIFrame;
import com.alinks.modbus.core.frame.ModbusFrame;
import com.alinks.modbus.core.frame.RtuFrame;
import com.alinks.modbus.core.frame.TcpFrame;
import com.alinks.modbus.core.utils.ASCIIUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ASCIIModbusCodec extends AbstractModbusCodec<ASCIIFrame.Request, ASCIIFrame.Response> {

    public ASCIIFrame.Request decode(ByteBuf in) {
        int readLength = in.readableBytes();
        ASCIIFrame.Request request = null;

        //.要把接受的bytes还原 ascii字符
        // 将ascii字符转成对应的数字,放入buf
        StringBuffer hexBuf = new StringBuffer();
        for (int i = 0; i < readLength; i++) {
            hexBuf.append(Integer.toHexString(in.readByte()));
        }

        String hex = hexBuf.toString();
        String compareHex = hex.toUpperCase();
        if (compareHex.startsWith(ASCIIFrame.PREFX) && compareHex.endsWith(ASCIIFrame.SUFFIX)) {
            //ascii对应处理
            String ascii = ASCIIUtil.convertHexToString(hex.substring(2, compareHex.lastIndexOf(ASCIIFrame.SUFFIX)));
            ByteBuf buffer = ByteBufAllocator.DEFAULT.heapBuffer(ascii.length() / 2);
            for (int i = 0, len = ascii.length() - 1; i < len; i += 2) {
                buffer.writeByte((byte)Integer.parseInt(ascii.substring(i, i+2), 16));
            }

            request = ASCIIFrame.Request.builder()
                    .header(ASCIIFrame.ASCIIHeader.builder()
                            .unitId(buffer.readByte())
                            .build())
                    .body(super.body(buffer))
                    .lrc(buffer.readByte())
                    .prefix((byte) 0x3a)
                    .suffix1((byte) 0x0d)
                    .suffix2((byte) 0x0a)
                    .build();
            request.setReadLength((readLength - 5)/2);

            //是否缓存
            buffer.release();
        }

        request.check();

        return request;
    }

    public void encode(ASCIIFrame.Response response, ByteBuf out) {
        if (response.getExcept() == null) {
            out.writeByte(response.getPrefix());
            out.writeBytes(response.getHeader().getHeaderBytes());
            body(response.getBody(), out);
            out.writeBytes(ASCIIUtil.byteAsciiToBytes(response.getLrc()));
            out.writeByte(response.getSuffix1());
            out.writeByte(response.getSuffix2());
        } else {
            //异常信息处理
            out.writeByte(response.getPrefix());
            out.writeBytes(response.getHeader().getHeaderBytes());
            out.writeBytes(ASCIIUtil.byteAsciiToBytes(response.getExcept().getFunc()));
            out.writeBytes(ASCIIUtil.byteAsciiToBytes(response.getExcept().getExceptCode().getCode()));
            out.writeByte(response.getSuffix1());
            out.writeByte(response.getSuffix2());
        }
    }

    @Override
    protected void body(ModbusFrame.ResponseBody body, ByteBuf out) {
        out.writeBytes(ASCIIUtil.byteAsciiToBytes(body.getFunc()));
        switch (body.getFunc()) {
            case 1:
            case 2:
            case 3:
            case 4: {
                out.writeBytes(ASCIIUtil.byteAsciiToBytes(body.getReturnLength()));
                if (body.getData() != null && body.getData().length > 0) {
                    for (int i = 0, len = body.getData().length; i < len; i++) {
                        out.writeBytes(ASCIIUtil.byteAsciiToBytes(body.getData()[i]));
                    }
                }
            } break;
            case 5:
            case 6: {
                out.writeBytes(ASCIIUtil.shortAsciiToBytes(body.getInAddress()));
                out.writeBytes(ASCIIUtil.shortAsciiToBytes(body.getInData()[0]));
                out.writeBytes(ASCIIUtil.shortAsciiToBytes(body.getInData()[1]));
            } break;
            case 8: {

            } break;
            case 11: break;
            case 12: break;
            case 15:
            case 16: {
                out.writeBytes(ASCIIUtil.shortAsciiToBytes(body.getInAddress()));
                out.writeBytes(ASCIIUtil.shortAsciiToBytes(body.getRegisterCount()));
            } break;
            case 17: break;
            default: break;
        }
    }

}
